package com.codeoss.framework.workflow.service.impl;

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.codeoss.framework.expression.Expression;
import com.codeoss.framework.expression.IScriptServiceStore;
import com.codeoss.framework.workflow.context.WorkflowContext;
import com.codeoss.framework.workflow.def.LineDef;
import com.codeoss.framework.workflow.def.NodeDef;
import com.codeoss.framework.workflow.def.WorkflowDef;
import com.codeoss.framework.workflow.service.ILineService;
import com.codeoss.framework.workflow.service.INodeService;
import com.codeoss.module.workflow.model.WorkflowActivity;
import com.codeoss.module.workflow.model.WorkflowActivityInstance;
import com.codeoss.module.workflow.model.WorkflowProcess;
import com.codeoss.module.workflow.model.WorkflowToken;
import com.codeoss.module.workflow.service.IWorkflowActivityInstanceService;
import com.codeoss.module.workflow.service.IWorkflowActivityService;
import com.codeoss.module.workflow.service.IWorkflowTokenService;

public class AbstractNodeService implements INodeService {
	@Autowired
	private ILineService lineService;
    @Autowired
    private IWorkflowActivityInstanceService workflowActivityInstanceService;
    @Autowired
    private IWorkflowActivityService workflowActivityService;
    @Autowired
    private IScriptServiceStore scriptServiceStore;
    @Autowired
    private IWorkflowTokenService workflowTokenService;
	@Override
	@Transactional
	public void start(WorkflowContext workflowContext) {
		// TODO Auto-generated method stub
		WorkflowProcess workflowProcess=workflowContext.getWorkflowProcess();
		NodeDef nodeDef=workflowContext.getNodeDef();
		
		QueryWrapper<WorkflowActivity> activityQuery=new QueryWrapper<WorkflowActivity>();
		activityQuery.eq("workflow_workflow_id", workflowProcess.getWorkflowWorkflowId());
		activityQuery.eq("node_id", nodeDef.getId());
		
		
		WorkflowActivity workflowActivity=workflowActivityService.getOne(activityQuery);
		workflowContext.setWorkflowActivity(workflowActivity);
		
		WorkflowActivityInstance workflowActivityInstance=new WorkflowActivityInstance();
		workflowActivityInstance.setWorkflowProcessId(workflowProcess.getId());
		workflowActivityInstance.setWorkflowActivityId(workflowActivity.getId());
		workflowActivityInstance.setStartDate(new Timestamp(System.currentTimeMillis()));
		workflowActivityInstance.setState("DR");
		workflowActivityInstance.setName(workflowActivity.getName());
		workflowActivityInstanceService.insert(workflowActivityInstance);
		
		workflowContext.setWorkflowActivityInstance(workflowActivityInstance);
		workflowContext.setBizKey(workflowProcess.getBizKey());
		
		WorkflowToken workflowToken=workflowContext.getWorkflowToken();
		workflowToken.setWorkflowActivityInstanceId(workflowActivityInstance.getId());
		workflowTokenService.update(workflowToken);
		
        executeStartExpression(workflowContext);
		
		execute(workflowContext);
	}
   
	@Transactional
	protected void executeStartExpression(WorkflowContext workflowContext) {
		NodeDef nodeDef=workflowContext.getNodeDef();
		Expression expression=nodeDef.getStartEventExpression();
		if(expression!=null) {
			Map<String,Object> bindingMap=new HashMap<String,Object>();
			bindingMap.put("workflowContext", workflowContext);
			scriptServiceStore.getScriptService(expression).eval(expression.getScript(), bindingMap);	
		}
	}
	
	
	@Override
	@Transactional
	public void execute(WorkflowContext workflowContext) {
		// TODO Auto-generated method stub
		end(workflowContext);
	}
	

	@Override
	@Transactional
	public void end(WorkflowContext workflowContext) {
		// TODO Auto-generated method stub
		LineDef lineDef=getDefaultLeaveTransition(workflowContext);
		end(workflowContext,lineDef);
	}

	@Override
	@Transactional
	public void end(WorkflowContext workflowContext, String transitionName) {
		// TODO Auto-generated method stub
		NodeDef nodeDef= workflowContext.getNodeDef();
		WorkflowDef workflowDef=nodeDef.getWorkflowDef();
		List<LineDef> lineDefList=workflowDef.getLineList();
		for(int i=0;i<lineDefList.size();i++) {
			LineDef lineDef=lineDefList.get(i);
			if(lineDef.getName().equals(transitionName)) {
				end(workflowContext,lineDef);
				break;
			}
		}
	}
	
	@Transactional
	public void end(WorkflowContext workflowContext, LineDef lineDef) {
		// TODO Auto-generated method stub
		WorkflowActivityInstance workflowActivityInstance=workflowContext.getWorkflowActivityInstance();
		workflowActivityInstance.setEndDate(new Timestamp(System.currentTimeMillis()));
		workflowActivityInstance.setState("CO");
		workflowActivityInstanceService.update(workflowActivityInstance);
		executeEndExpression(workflowContext);
		
		lineService.take(workflowContext, lineDef);
	}
	
	public LineDef getDefaultLeaveTransition(WorkflowContext workflowContext) {
		NodeDef nodeDef= workflowContext.getNodeDef();
		WorkflowDef workflowDef=nodeDef.getWorkflowDef();
		List<LineDef> lineDefList=workflowDef.getLineList();
		for(int i=0;i<lineDefList.size();i++) {
			LineDef lineDef=lineDefList.get(i);
			if(lineDef.getFromNodeId().equals(nodeDef.getId())) {
				return lineDef;
			}
		}
		return null;
	}
	
	@Transactional
	protected void executeEndExpression(WorkflowContext workflowContext) {
		NodeDef nodeDef=workflowContext.getNodeDef();
		Expression expression=nodeDef.getEndEventExpression();
		if(expression!=null) {
			Map<String,Object> bindingMap=new HashMap<String,Object>();
			bindingMap.put("workflowContext", workflowContext);
			scriptServiceStore.getScriptService(expression).eval(expression.getScript(), bindingMap);	
		}
	}
}
